package Game;

import java.util.ArrayList;
import java.util.Random;

import android.util.Log;

public class Game {

	private Tile[][] board;
	private int[][] moves;
	private int[][] attacks;
	private int[][] tempBoard;
	private int boardSize;
	private boolean blacksTurn;
	private ArrayList<Piece> whitePieces;
	private ArrayList<Piece> blackPieces;
	public final static int MOVE = 1;
	public final static int ATTACK = 2;
	public final static int MOVE_ATTACK = 3;
	public final static int NW = 0;
	public final static int N = 1;
	public final static int NE = 2;
	public final static int W = 3;
	public final static int E = 4;
	public final static int SW = 5;
	public final static int S = 6;
	public final static int SE = 7;
	public final static int RUN_GAME = 0;
	public final static int TERRAIN_SETUP = 1;
	public final static int PIECE_SETUP = 2;

	private int setup;
	int[] directions = { NW, N, NE, W, E, SW, S, SE };

	public Game() {
		boardSize = 8;
		board = new Tile[boardSize][boardSize];
		moves = new int[boardSize][boardSize];
		tempBoard = new int[boardSize][boardSize];
		attacks = new int[boardSize][boardSize];
		resetBoard();
		resetAttackBoard();
		resetTempBoard();
		resetMoveBoard();
		addPieces();
		// createSampleBoard();
		createSetupBoard();
		blacksTurn = true;
		setup = TERRAIN_SETUP;
	}

	public boolean checkTerrainDrop(int row, int col) {
		if (blacksTurn) {
			return row >= 4 && row <= 7;
		} else {
			return row >= 0 && row <= 3;
		}
	}

	public Tile[][] getBoard() {
		return board;
	}

	private void resetBoard() {
		for (int i = 0; i < boardSize; i++) {
			for (int j = 0; j < boardSize; j++) {

				board[i][j] = new Grass();
			}
		}
	}

	private void resetTempBoard() {
		for (int i = 0; i < boardSize; i++) {
			for (int j = 0; j < boardSize; j++) {
				tempBoard[i][j] = -1;
			}
		}
	}

	private void resetMoveBoard() {
		for (int i = 0; i < boardSize; i++) {
			for (int j = 0; j < boardSize; j++) {
				moves[i][j] = -1;
			}
		}
	}

	private void resetAttackBoard() {
		for (int i = 0; i < boardSize; i++) {
			for (int j = 0; j < boardSize; j++) {
				attacks[i][j] = -1;
			}
		}
	}

	private void getTrebuchetAttack(int row, int col, int range,
			int lastDirection, boolean isBlack) {
		if (row >= 0 && row < 8 && col >= 0 && col < 8) {
			if (range >= 0) {

				if (isBlack) {
					if (lastDirection != -1
							&& board[row][col].getPiece() != null
							&& board[row][col].getPiece().isBlack != isBlack) {
						attacks[row][col] = 1;
					}
					switch (lastDirection) {
					case N:
						getTrebuchetAttack(row - 1, col, range - 1, N, isBlack);
						break;
					case NE:
						getTrebuchetAttack(row - 1, col + 1, range - 1, NE,
								isBlack);
						break;
					case NW:
						getTrebuchetAttack(row - 1, col - 1, range - 1, NW,
								isBlack);
						break;
					case -1:
						int count = 0;
						for (int c = -1; c <= 1; c++) {
							getTrebuchetAttack(row - 1, col + c, range - 1,
									directions[count], isBlack);
							count++;
						}

					}
				} else {
					if (lastDirection != -1
							&& board[row][col].getPiece() != null
							&& board[row][col].getPiece().isBlack) {
						attacks[row][col] = 1;
					}
					switch (lastDirection) {
					case S:
						getTrebuchetAttack(row + 1, col, range - 1, S, isBlack);
						break;
					case SE:
						getTrebuchetAttack(row + 1, col + 1, range - 1, SE,
								isBlack);
						break;
					case SW:
						getTrebuchetAttack(row + 1, col - 1, range - 1, SW,
								isBlack);
						break;
					case -1:
						int count = 5;
						for (int c = -1; c <= 1; c++) {
							getTrebuchetAttack(row + 1, col + c, range - 1,
									directions[count], isBlack);
							count++;
						}
					}
				}

			}
		}
	}

	private void getRangeAttack(int row, int col, int range, int lastDirection,
			boolean isBlack) {

		if (row >= 0 && row < 8 && col >= 0 && col < 8) {
			if (range > 0) {
				if (lastDirection != -1 && board[row][col].getPiece() != null
						&& board[row][col].getPiece().isBlack != isBlack) {
					attacks[row][col] = 1;
				}
				switch (lastDirection) {
				case N:
					for (int c = -1; c <= 1; c++) {
						getRangeAttack(row - 1, col + c, range - 1, N, isBlack);
					}
					break;
				case S:
					for (int c = -1; c <= 1; c++) {
						getRangeAttack(row + 1, col + c, range - 1, S, isBlack);
					}
					break;
				case E:
					for (int r = -1; r <= 1; r++) {
						getRangeAttack(row + r, col + 1, range - 1, E, isBlack);
					}
					break;
				case W:
					for (int r = -1; r <= 1; r++) {
						getRangeAttack(row + r, col - 1, range - 1, W, isBlack);
					}
					break;
				case NE:
					getRangeAttack(row - 1, col + 1, range - 1, NE, isBlack);
					break;
				case SE:
					getRangeAttack(row + 1, col + 1, range - 1, SE, isBlack);
					break;
				case NW:
					getRangeAttack(row - 1, col - 1, range - 1, NW, isBlack);
					break;
				case SW:
					getRangeAttack(row + 1, col - 1, range - 1, SW, isBlack);
					break;
				case -1:
					int counter = 0;
					for (int r = -1; r <= 1; r++) {
						for (int c = -1; c <= 1; c++) {
							if (!(r == 0 && c == 0) && row + r >= 0
									&& row + r < 8 && col + c >= 0
									&& col + c < 8) {
								getRangeAttack(row + r, col + c, range - 1,
										directions[counter], isBlack);
								counter++;
							}
						}
					}
					break;
				default:
					break;
				}
			} else {
				if (board[row][col].getPiece() != null) {
					attacks[row][col] = 1;
				}

			}
		}
	}

	private void makeDragonMove(int row, int col, int lastDirection,
			boolean isBlack) {
		boolean dragonBlock = false;
		if (row >= 0 && row < 8 && col >= 0 && col < 8) {
			if (board[row][col].getPiece() != null) {
				if (board[row][col].getPiece().getClass() == Dragon.class) {
					dragonBlock = true;
				} else {
					dragonBlock = false;
				}
			}
			if (lastDirection != -1) {
				moves[row][col] = 1;
				if (board[row][col].getPiece() != null) {
					if (board[row][col].getClass() == Forest.class) {
						if (board[row][col].getPiece().getClass() != Dragon.class) {
							moves[row][col] = -1;
						} else {
							attacks[row][col] = 1;
						}

					} else {
						if (board[row][col].getPiece().isBlack != isBlack) {
							attacks[row][col] = 1;
						}
					}
				}
			}
			if (lastDirection == -1) {
				dragonBlock = false;
			}
			if (!dragonBlock) {
				switch (lastDirection) {
				case N:
					makeDragonMove(row - 1, col, N, isBlack);
					break;
				case S:
					makeDragonMove(row + 1, col, S, isBlack);
					break;
				case E:
					makeDragonMove(row, col + 1, E, isBlack);
					break;
				case W:
					makeDragonMove(row, col - 1, W, isBlack);
					break;
				case NE:
					makeDragonMove(row - 1, col + 1, NE, isBlack);
					break;
				case SE:
					makeDragonMove(row + 1, col + 1, SE, isBlack);
					break;
				case NW:
					makeDragonMove(row - 1, col - 1, NW, isBlack);
					break;
				case SW:
					makeDragonMove(row + 1, col - 1, SW, isBlack);
					break;
				case -1:
					int counter = 0;
					for (int r = -1; r <= 1; r++) {
						for (int c = -1; c <= 1; c++) {
							if (!(r == 0 && c == 0)) {
								if (row + r >= 0 && row + r < 8 && col + c >= 0
										&& col + c < 8) {
									makeDragonMove(row + r, col + c,
											directions[counter], isBlack);

								}
								counter++;
							}
						}
					}
					break;
				default:
					break;
				}
			}
		}

	}

	public int[][] getMoves(int row, int col) {
		resetTempBoard();
		resetMoveBoard();
		resetAttackBoard();
		moves[row][col] = 10;
		Piece targetPiece = board[row][col].getPiece();
		if (targetPiece != null) {
			if (targetPiece.getClass() == Dragon.class) {
				makeDragonMove(row, col, -1, targetPiece.isBlack);
			} else if (targetPiece.getClass() == Trebuchet.class) {
				moveTrebuchet(row, col);
			} else {
				makeMove(targetPiece.getMovement(), row, col,
						targetPiece.isBlack);
			}
		}
		moves[row][col] = -1;
		if (targetPiece != null && targetPiece instanceof RangedPiece) {
			RangedPiece rangedPiece = (RangedPiece) targetPiece;
			if (rangedPiece.getClass() == Trebuchet.class) {
				getTrebuchetAttack(row, col, rangedPiece.getAttackRange(), -1,
						rangedPiece.isBlack);
			} else {
				getRangeAttack(row, col, rangedPiece.getAttackRange(), -1,
						rangedPiece.isBlack);
			}

		}
		parseBoard(row, col);
		return tempBoard;
	}

	private void parseBoard(int row, int col) {
		if (row >= 0 && row < 8 && col >= 0 && col < 8) {
			Piece movingPiece = board[row][col].getPiece();
			Piece targetPiece = null;
			for (int r = 0; r < 8; r++) {
				for (int c = 0; c < 8; c++) {
					if (board[r][c].getPiece() != null) {
						targetPiece = board[r][c].getPiece();
					} else {
						targetPiece = null;
					}
					if (moves[r][c] >= 0) {
						if (attacks[r][c] >= 0) {
							if (targetPiece.isBlack != movingPiece.isBlack) {
								if (movingPiece instanceof RangedPiece) {
									// Piece is ranged
									if (targetPiece.getPower() - 1 <= movingPiece
											.getPower()
											|| targetPiece.getClass() == Dragon.class
											|| targetPiece.getClass() == King.class) {
										tempBoard[r][c] = ATTACK;
									}
								} else {
									if (movingPiece.getClass() == LightHorse.class
											|| movingPiece.getClass() == HeavyHorse.class) {
										if (targetPiece.getClass() == Spearmen.class) {
											Spearmen targetSpearPiece = (Spearmen) targetPiece;
											if (!targetSpearPiece.isDefending()) {
												tempBoard[r][c] = MOVE_ATTACK;
											}
										} else if (targetPiece.getClass() == Catapult.class
												|| targetPiece.getClass() == Trebuchet.class) {
											tempBoard[r][c] = MOVE_ATTACK;
										} else {
											if (targetPiece.getPower() - 1 <= movingPiece
													.getPower() || targetPiece.getClass() == King.class) {
												tempBoard[r][c] = MOVE_ATTACK;
											}
										}
									} else if (movingPiece instanceof King) {
										tempBoard[r][c] = MOVE_ATTACK;
									} else {
										if (targetPiece.getPower() - 1 <= movingPiece
												.getPower()) {
											tempBoard[r][c] = MOVE_ATTACK;
										}
									}
								}
							}
						} else {
							if (targetPiece == null) {
								tempBoard[r][c] = MOVE;
							}
						}
					} else if (attacks[r][c] >= 0) {
						if (targetPiece.isBlack != movingPiece.isBlack) {
							if (targetPiece.getPower() - 1 <= movingPiece
									.getPower()
									|| targetPiece.getClass() == Dragon.class) {
								tempBoard[r][c] = ATTACK;
							}
						}
					}
				}
			}
		}
	}

	private void moveTrebuchet(int row, int col) {
		for (int r = -1; r <= 1; r++) {
			for (int c = -1; c <= 1; c++) {
				if (!(r == 0 && c == 0)) {
					if (row + r >= 0 && row + r < 8 && col + c >= 0
							&& col + c < 8) {
						if (board[row + r][col + c].getClass() != Mountain.class
								&& board[row + r][col + c].getPiece() == null) {
							moves[row + r][col + c] = 1;
						}
					}
				}
			}
		}
	}

	public boolean viablePiece(int row, int col) {
		if (board[row][col].getPiece() != null
				&& board[row][col].getPiece().isBlack == blacksTurn) {
			return true;
		} else {
			return false;
		}
	}

	private void makeMove(int movesLeft, int row, int col, boolean isBlack) {

		if (movesLeft > 0) {
			for (int r = -1; r <= 1; r++) {
				for (int c = -1; c <= 1; c++) {
					if (!(r == 0 && c == 0)) {
						if (row + r >= 0 && row + r < 8 && col + c >= 0
								&& col + c < 8) {
							Tile nextTile = board[row + r][col + c];
							if (nextTile.getClass() != Mountain.class) {
								if (moves[row + r][col + c] < movesLeft - 1) {

									if (nextTile.getClass() == Forest.class) {
										if (movesLeft > 1) {
											moves[row + r][col + c] = movesLeft - 2;
										} else {
											moves[row + r][col + c] = movesLeft - 1;
										}
										if (nextTile.getPiece() == null) {
											makeMove(movesLeft - 2, row + r,
													col + c, isBlack);
										} else {
											if (nextTile.getPiece().isBlack != isBlack) {
												attacks[row + r][col + c] = 1;
											}
										}
									} else if (nextTile.getClass() == Water.class) {
										moves[row + r][col + c] = 0;
										if (nextTile.getPiece() != null) {
											if (nextTile.getPiece().isBlack != isBlack) {
												attacks[row + r][col + c] = 1;
											}
										}
									} else {
										moves[row + r][col + c] = movesLeft - 1;
										if (nextTile.getPiece() == null) {
											makeMove(movesLeft - 1, row + r,
													col + c, isBlack);
										} else {
											if (nextTile.getPiece().isBlack != isBlack) {
												attacks[row + r][col + c] = 1;
											}
										}
									}
								}
							}
						}
					}
				}
			}
		}
	}

	private void addPieces() {
		whitePieces = new ArrayList<Piece>();
		whitePieces.add(new King(false));
		whitePieces.add(new Rabble(false));
		whitePieces.add(new Spearmen(false));
		whitePieces.add(new Crossbowman(false));
		whitePieces.add(new LightHorse(false));
		whitePieces.add(new HeavyHorse(false));
		whitePieces.add(new Elephant(false));
		whitePieces.add(new Catapult(false));
		whitePieces.add(new Trebuchet(false));
		whitePieces.add(new Dragon(false));

		blackPieces = new ArrayList<Piece>();
		blackPieces.add(new King(true));
		blackPieces.add(new Rabble(true));
		blackPieces.add(new Spearmen(true));
		blackPieces.add(new Crossbowman(true));
		blackPieces.add(new LightHorse(true));
		blackPieces.add(new HeavyHorse(true));
		blackPieces.add(new Elephant(true));
		blackPieces.add(new Catapult(true));
		blackPieces.add(new Trebuchet(true));
		blackPieces.add(new Dragon(true));

	}

	public void doMove(int startRow, int startCol, int endRow, int endCol) {

		Piece movingPiece = board[startRow][startCol].getPiece();
		Piece targetPiece = board[endRow][endCol].getPiece();
		if (movingPiece.getClass() == Spearmen.class) {
			Spearmen spearmenPiece = (Spearmen) movingPiece;
			spearmenPiece.setDefending(false);
		} else {
			if (blacksTurn) {
				Spearmen piece = (Spearmen) blackPieces.get(2);
				piece.setDefending(true);
			} else {
				Spearmen piece = (Spearmen) whitePieces.get(2);
				piece.setDefending(true);
			}
		}
		if (targetPiece == null) {
			board[endRow][endCol].setPiece(movingPiece);
			board[startRow][startCol].setPiece(null);
		} else {
			if (movingPiece instanceof RangedPiece) {
				board[endRow][endCol].setPiece(null);
			} else {
				board[endRow][endCol].setPiece(movingPiece);
				board[startRow][startCol].setPiece(null);
			}
		}
		if (setup == Game.RUN_GAME) {
			blacksTurn = !blacksTurn;
		}
	}

	public void terrainSwap(int startRow, int startCol, int endRow, int endCol) {
		Tile startTile = board[startRow][startCol];
		Tile endTile = board[endRow][endCol];
		board[startRow][startCol] = endTile;
		board[endRow][endCol] = startTile;
	}

	public int[][] setupMoves(int row, int col) {
		resetMoveBoard();
		int startRow;
		int endRow;
		Piece currentPiece = board[row][col].getPiece();
		if (blacksTurn) {
			startRow = 4;
			endRow = 7;
		} else {
			startRow = 0;
			endRow = 3;
		}
		if (currentPiece != null) {
			for (int r = startRow; r <= endRow; r++) {
				for (int c = 0; c <= 7; c++) {
					if (currentPiece.getClass() != Dragon.class) {
						if (board[r][c].getClass() != Mountain.class
								&& board[r][c].getPiece() == null) {
							moves[r][c] = MOVE;
						}
					} else {
						if (board[r][c].getPiece() == null) {
							moves[r][c] = MOVE;
						}
					}
				}
			}
		}
		return moves;
	}

	private void createSetupBoard() {
		// WHITE TERRAIN
		board[0][0] = new Mountain();
		board[0][1] = new Mountain();
		board[0][2] = new Mountain();
		board[0][3] = new Mountain();
		board[0][4] = new Mountain();
		board[0][5] = new Mountain();

		board[1][0] = new Forest();
		board[1][1] = new Forest();
		board[1][2] = new Forest();
		board[1][3] = new Forest();
		board[1][4] = new Forest();
		board[1][5] = new Forest();

		board[2][0] = new Water();
		board[2][1] = new Water();
		board[2][2] = new Water();
		board[2][3] = new Water();
		board[2][4] = new Water();

		// BLACK TERRAIN
		board[7][0] = new Mountain();
		board[7][1] = new Mountain();
		board[7][2] = new Mountain();
		board[7][3] = new Mountain();
		board[7][4] = new Mountain();
		board[7][5] = new Mountain();

		board[6][0] = new Forest();
		board[6][1] = new Forest();
		board[6][2] = new Forest();
		board[6][3] = new Forest();
		board[6][4] = new Forest();
		board[6][5] = new Forest();

		board[5][0] = new Water();
		board[5][1] = new Water();
		board[5][2] = new Water();
		board[5][3] = new Water();
		board[5][4] = new Water();
	}

	private void createSampleBoard() {
		board[3][3] = new Mountain();
		board[6][3] = new Mountain();
		board[4][7] = new Mountain();
		board[2][5] = new Mountain();
		board[3][4] = new Mountain();
		board[5][3] = new Mountain();
		board[0][5] = new Mountain();
		board[0][7] = new Mountain();
		board[1][1] = new Mountain();
		board[2][2] = new Mountain();
		board[5][0] = new Mountain();
		board[5][2] = new Mountain();

		board[7][7] = new Forest();
		board[2][7] = new Forest();
		board[6][7] = new Forest();
		board[7][1] = new Forest();
		board[5][4] = new Forest();
		board[3][2] = new Forest();
		board[5][1] = new Forest();
		board[4][2] = new Forest();
		board[1][2] = new Forest();
		board[2][1] = new Forest();
		board[1][7] = new Forest();
		board[3][7] = new Forest();

		board[0][6] = new Water();
		board[1][6] = new Water();
		board[2][6] = new Water();
		board[3][6] = new Water();
		board[3][5] = new Water();
		board[4][5] = new Water();
		board[5][5] = new Water();
		board[6][5] = new Water();
		board[7][5] = new Water();
		board[7][6] = new Water();

		board[1][2].setPiece(whitePieces.get(0));
		board[2][1].setPiece(whitePieces.get(1));
		board[2][4].setPiece(whitePieces.get(2));
		board[2][3].setPiece(whitePieces.get(3));
		board[0][3].setPiece(whitePieces.get(4));
		board[1][5].setPiece(whitePieces.get(5));
		board[3][6].setPiece(whitePieces.get(6));
		board[3][2].setPiece(whitePieces.get(7));
		board[0][4].setPiece(whitePieces.get(8));
		board[1][0].setPiece(whitePieces.get(9));

		board[7][1].setPiece(blackPieces.get(0));
		board[6][0].setPiece(blackPieces.get(1));
		board[5][1].setPiece(blackPieces.get(2));
		board[4][6].setPiece(blackPieces.get(3));
		board[4][0].setPiece(blackPieces.get(4));
		board[5][6].setPiece(blackPieces.get(5));
		board[4][3].setPiece(blackPieces.get(6));
		board[6][2].setPiece(blackPieces.get(7));
		board[5][4].setPiece(blackPieces.get(8));
		board[7][7].setPiece(blackPieces.get(9));
	}

	private void pieceSetup() {
		if (blacksTurn) {
			int counter = 0;
			Log.e("piecesetup", "setting up black pieces");
			for (int r = 4; r <= 7; r++) {
				for (int c = 0; c <= 7; c++) {
					if (board[r][c].getPiece() == null && counter < 10) {
						if (board[r][c].getClass() != Mountain.class) {
							board[r][c].setPiece(blackPieces.get(counter));
							counter++;
						} else {
							if (counter == 9) {
								board[r][c].setPiece(blackPieces.get(counter));
								counter++;
							}
						}

					}
				}
			}

		} else {
			int counter = 0;

			for (int r = 0; r <= 3; r++) {
				for (int c = 0; c <= 7; c++) {
					if (board[r][c].getPiece() == null && counter < 10) {
						if (board[r][c].getClass() != Mountain.class) {
							board[r][c].setPiece(whitePieces.get(counter));
							counter++;
						} else {
							if (counter == 9) {
								board[r][c].setPiece(whitePieces.get(counter));
								counter++;
							}
						}

					}
				}
			}

		}
	}

	public void setupNextStep() {

		switch (setup) {
		case TERRAIN_SETUP:
			pieceSetup();
			setup = PIECE_SETUP;
			break;
		case PIECE_SETUP:
			if (blacksTurn) {
				setup = TERRAIN_SETUP;
				blacksTurn = !blacksTurn;
			} else {
				setup = RUN_GAME;
				Random rand = new Random();
				int start = rand.nextInt(2);
				if (start == 0) {
					blacksTurn = true;
				} else {
					blacksTurn = false;
				}
			}
			break;
		case RUN_GAME:
			break;
		}
	}

	public int getSetup() {
		return setup;
	}

	public boolean getTurn() {
		return blacksTurn;
	}
}